using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using PowerManage.Entity;
using PowerManage.Entity.Enums;

namespace PowerManage.EntityFrameworkCore;

/**
 * 主键是long
 * 实现有泛型的IdentityDbContext 是为了自定义Identity表名称
 */
public class ApplicationDbContext : IdentityDbContext<EleUser, EleRole, long, EleUserClaim, EleUserRole, EleUserLogin,
    EleRoleClaim, EleUserToken>
{
    #region 增加实体属性

    public DbSet<ElePermission> ElePermission { get; set; }
    public DbSet<EleRolePermission> EleRolePermission { get; set; }
    public DbSet<EleAuditLog> EleAuditLog { get; set; }

    #endregion

    //DbContextOptions 是一个泛型类，用于配置数据库连接和其他选项
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
    {
    }

    /**
     * OnConfiguring 方法在 DbContext 构造函数之后立即调用，此时数据库连接尚未建立
     */
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        // 用于启用 Npgsql 客户端与 Postgres 服务器之间的时间戳行为  在6.0 之前，读取时将转换为本地时间戳
        //解决报错：timestamp with time zone' literal cannot be generated for Local DateTime: a UTC DateTime is required 
        //AppContext.SetSwitch 用于设置全局的应用程序上下文开关 与数据库连接和框架行为相关，应该在数据库连接建立之前设置
        AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);
        AppContext.SetSwitch("Npgsql.DisableDateTimeInfinityConversions", true);
        base.OnConfiguring(optionsBuilder);
    }

    /**
     * 重写OnModelCreating 为了在模型构建过程中对模型进行自定义配置
     * OnModelCreating 方法在 OnConfiguring 之后调用，此时数据库连接已经建立，并且模型即将被构建
     */
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        //配置实体类型映射到的表名
        modelBuilder.Entity<EleUser>().ToTable("EleUser");
        modelBuilder.Entity<EleUserLogin>().ToTable("EleUserLogin");
        modelBuilder.Entity<EleUserClaim>().ToTable("EleUserClaim");
        modelBuilder.Entity<EleUserToken>().ToTable("EleUserToken");
        modelBuilder.Entity<EleRole>().ToTable("EleRole");
        modelBuilder.Entity<EleRoleClaim>().ToTable("EleRoleClaim");
        modelBuilder.Entity<EleUserRole>().ToTable("EleUserRole");

        //注意：如果你只在实体类中使用注解，并且没有在 OnModelCreating 方法中使用 Fluent API 配置这些字段，那么注解会生效。
        //如果同时使用 Fluent API，那么 Fluent API 的配置会覆盖注解的配置 因为在源码里有对EleUser做处理 如下为源码中的处理
        // builder.Entity<TUser>(b =>
        // {
        //     b.HasKey(u => u.Id);
        //     b.HasIndex(u => u.NormalizedUserName).HasDatabaseName("UserNameIndex").IsUnique();
        //     b.HasIndex(u => u.NormalizedEmail).HasDatabaseName("EmailIndex");
        //     b.ToTable("AspNetUsers");
        //     b.Property(u => u.ConcurrencyStamp).IsConcurrencyToken();
        //
        //     b.Property(u => u.UserName).HasMaxLength(256);
        //     b.Property(u => u.NormalizedUserName).HasMaxLength(256);
        //     b.Property(u => u.Email).HasMaxLength(256);
        //     b.Property(u => u.NormalizedEmail).HasMaxLength(256);
        //     b.Property(u => u.PhoneNumber).HasMaxLength(256);

        //指定长度字段
        modelBuilder.Entity<EleUser>(entity =>
        {
            entity.Property(user => user.UserName).HasMaxLength(100);
            entity.Property(user => user.NormalizedUserName).HasMaxLength(100);
        });

        //如果不使用lambda，可以使用匿名方法
        // modelBuilder.Entity<EleUser>(delegate(EntityTypeBuilder<EleUser> entity)
        // {
        //     entity.Property(user => user.UserName).HasMaxLength(100);
        //     entity.Property(user => user.NormalizedUserName).HasMaxLength(100);
        // });
        modelBuilder.Entity<EleRole>(entity =>
        {
            entity.Property(role => role.Name).HasMaxLength(100);
            entity.Property(role => role.NormalizedName).HasMaxLength(100);
        });

        //指定外键关系
        modelBuilder.Entity<EleRole>(entity =>
        {
            //指定角色和角色权限表 一对多
            //DeleteBehavior.Cascade 表示当删除一个 EleRole 实体时，所有相关的 EleRolePermission 实体也会被级联删除
            entity.HasMany<EleRolePermission>().WithOne().HasForeignKey(rolePermission => rolePermission.RoleId)
                .OnDelete(DeleteBehavior.Cascade);
        });
        modelBuilder.Entity<ElePermission>(entity =>
        {
            //指定权限和角色权限表 一对多
            entity.HasMany<EleRolePermission>().WithOne().HasForeignKey(rolePermission => rolePermission.PermissionId)
                .OnDelete(DeleteBehavior.Cascade);
        });

        //添加初始化代码 也可以在数据库初始化脚本中添加
        //modelBuilder.Entity<EleUser>().HasData(adminUser);指定表 插入数据
        //1 添加角色
        var adminRoleId = 1;
        modelBuilder.Entity<EleRole>().HasData(
            new EleRole
            {
                Id = adminRoleId,
                Name = "管理员",
                NormalizedName = "超级管理员".ToUpper(),
                Remark = "超级管理员",
                Status = RoleStatus.Normal,
                CreationTime = DateTime.Now
            });

        //2 添加用户
        var adminUserId = 1;
        var adminUser = new EleUser
        {
            Id = adminUserId,
            CreationTime = DateTime.Now,
            UserName = "admin",
            NormalizedUserName = "admin".ToUpper(),
            Email = "admin@qq.com",
            NormalizedEmail = "admin@qq.com".ToUpper(),
            TwoFactorEnabled = false, //用户的双因素认证未启用 如果设置为 true，用户需要通过两种验证方式（例如密码和手机验证码）才能登录
            EmailConfirmed = true,
            FullName = "管理员",
            PhoneNumber = "123456789",
            PhoneNumberConfirmed = false,
            //SecurityStamp：是一个用于存储安全标记的属性，通常是一个随机生成的字符串
            //作用：防止会话劫持，检测用户状态变化。
            //当用户登录后，系统会生成一个 SecurityStamp 并存储在用户记录中。
            // 会话劫持：在后续的请求中，系统会验证当前的 SecurityStamp 是否与存储在用户记录中的 SecurityStamp 相匹配。
            //         如果不匹配，系统会认为用户的会话可能被劫持，并采取相应的措施（如重新登录）
            //          生成和更新：在用户注册或更新重要属性时生成或更新 SecurityStamp
            SecurityStamp = Guid.NewGuid().ToString(),
            Status = UserStatus.Normal
        };
        var passwordHasher = new PasswordHasher<EleUser>();
        adminUser.PasswordHash = passwordHasher.HashPassword(adminUser, "123456");
        modelBuilder.Entity<EleUser>().HasData(adminUser);

        //3 添加用户角色
        modelBuilder.Entity<EleUserRole>()
            .HasData(new EleUserRole()
            {
                RoleId = adminRoleId,
                UserId = adminUserId
            });

        //4 添加权限
        var permissionList = new List<ElePermission>()
        {
            new ElePermission()
            {
                Id = 1,
                Name = "系统管理",
                Code = "system",
                Url = "system",
                Component = "",
                Icon = "el-icon-s-tools",
                Sort = 0,
                Remark = "系统管理",
                PermissionType = PermissionType.Menu,
                ApiMethod = "",
                ParentId = 0,
                Status = PermissionStatus.Normal,
                CreationTime = DateTime.Now
            },
            new ElePermission()
            {
                Id = 2,
                Name = "用户管理",
                Code = "system.user",
                Url = "user",
                Component = "views/documentation/index",
                Icon = "el-icon-user-solid",
                Sort = 0,
                Remark = "用户管理",
                PermissionType = PermissionType.Menu,
                ApiMethod = "",
                ParentId = 1,
                Status = PermissionStatus.Normal,
                CreationTime = DateTime.Now
            },
            new ElePermission()
            {
                Id = 3,
                Name = "角色管理",
                Code = "system.role",
                Url = "role",
                Component = "views/documentation/index",
                Icon = "peoples",
                Sort = 0,
                Remark = "角色管理",
                PermissionType = PermissionType.Menu,
                ApiMethod = "",
                ParentId = 1,
                Status = PermissionStatus.Normal,
                CreationTime = DateTime.Now
            },
            new ElePermission()
            {
                Id = 4,
                Name = "权限管理",
                Code = "system.permission",
                Url = "permission",
                Component = "views/documentation/index",
                Icon = "list",
                Sort = 0,
                Remark = "权限管理",
                PermissionType = PermissionType.Menu,
                ApiMethod = "",
                ParentId = 1,
                Status = PermissionStatus.Normal,
                CreationTime = DateTime.Now
            },
            new ElePermission()
            {
                Id = 5,
                Name = "角色权限",
                Code = "system.rolepermission",
                Url = "rolepermission",
                Component = "views/documentation/index",
                Icon = "example",
                Sort = 0,
                Remark = "角色权限",
                PermissionType = PermissionType.Menu,
                ApiMethod = "",
                ParentId = 1,
                Status = PermissionStatus.Normal,
                CreationTime = DateTime.Now
            },
            new ElePermission()
            {
                Id = 6,
                Name = "添加",
                Code = "system.user.add",
                Url = "",
                Component = "",
                Icon = "",
                PermissionType = PermissionType.Element,
                ApiMethod = "",
                Sort = 0,
                ParentId = 2,
                Status = PermissionStatus.Normal
            },
            new ElePermission()
            {
                Id = 7,
                Name = "编辑",
                Code = "system.user.edit",
                Url = "",
                Component = "",
                Icon = "",
                PermissionType = PermissionType.Element,
                ApiMethod = "",
                Sort = 0,
                ParentId = 2,
                Status = PermissionStatus.Normal
            },
            new ElePermission()
            {
                Id = 8,
                Name = "删除",
                Code = "system.user.delete",
                Url = "",
                Component = "",
                Icon = "",
                PermissionType = PermissionType.Element,
                ApiMethod = "",
                Sort = 0,
                ParentId = 2,
                Status = PermissionStatus.Normal
            },
            new ElePermission()
            {
                Id = 9,
                Name = "添加",
                Code = "system.role.add",
                Url = "",
                Component = "",
                Icon = "",
                PermissionType = PermissionType.Element,
                ApiMethod = "",
                Sort = 0,
                ParentId = 3,
                Status = PermissionStatus.Normal
            },
            new ElePermission()
            {
                Id = 10,
                Name = "编辑",
                Code = "system.role.edit",
                Url = "",
                Component = "",
                Icon = "",
                PermissionType = PermissionType.Element,
                ApiMethod = "",
                Sort = 0,
                ParentId = 3,
                Status = PermissionStatus.Normal
            },
            new ElePermission()
            {
                Id = 11,
                Name = "删除",
                Code = "system.role.delete",
                Url = "",
                Component = "",
                Icon = "",
                PermissionType = PermissionType.Element,
                ApiMethod = "",
                Sort = 0,
                ParentId = 3,
                Status = PermissionStatus.Normal
            },
            new ElePermission()
            {
                Id = 12,
                Name = "添加",
                Code = "system.permission.add",
                Url = "",
                Component = "",
                Icon = "",
                PermissionType = PermissionType.Element,
                ApiMethod = "",
                Sort = 0,
                ParentId = 4,
                Status = PermissionStatus.Normal
            },
            new ElePermission()
            {
                Id = 13,
                Name = "编辑",
                Code = "system.permission.edit",
                Url = "",
                Component = "",
                Icon = "",
                PermissionType = PermissionType.Element,
                ApiMethod = "",
                Sort = 0,
                ParentId = 4,
                Status = PermissionStatus.Normal
            },
            new ElePermission()
            {
                Id = 14,
                Name = "删除",
                Code = "system.permission.delete",
                Url = "",
                Component = "",
                Icon = "",
                PermissionType = PermissionType.Element,
                ApiMethod = "",
                Sort = 0,
                ParentId = 4,
                Status = PermissionStatus.Normal
            },
            new ElePermission()
            {
                Id = 15,
                Name = "更新",
                Code = "system.rolepermission.update",
                Url = "",
                Component = "",
                Icon = "",
                PermissionType = PermissionType.Element,
                ApiMethod = "",
                Sort = 0,
                ParentId = 5,
                Status = PermissionStatus.Normal
            },
            new ElePermission()
            {
                Id = 16,
                Name = "日志管理",
                Code = "log.auditlog",
                Url = "log",
                Component = "",
                Icon = "bug",
                PermissionType = PermissionType.Menu,
                ApiMethod = "",
                Sort = 0,
                ParentId = 0,
                Status = PermissionStatus.Normal
            },
        };
        modelBuilder.Entity<ElePermission>().HasData(permissionList);

        //5 添加角色权限
        var rolePermissionList = new List<EleRolePermission>();
        foreach (var permission in permissionList)
        {
            rolePermissionList.Add(new EleRolePermission()
            {
                Id = permission.Id,
                RoleId = adminRoleId,
                PermissionId = permission.Id
            });
        }

        modelBuilder.Entity<EleRolePermission>().HasData(rolePermissionList);
    }
}